//This file contains two object definitions:
//  Stimulus
//  StimulusSet

class Stimulus {
  //A stimulus is the thing (e.g., circle) drawn within the StimulusSet object
  //A StimulusSet object contains a set of Stimuli defined as an Arraylist
  PVector position;
  float area;
  float rad;
  
  Stimulus(float _rad, PVector _position) {
    position = _position;
    area = PI*pow(_rad,2);
    rad = _rad;
  }
  void drawStimulus() {
    //Colors anyone?
    noStroke();
    ellipse(position.x,position.y,rad,rad);
  }
}

class StimulusSet {
  //StimulusSet objects are the buttons / containers presented during
  //presentation of the sample stimulus and comparison stimuli
  
  int num;
  int area;
  int position;
  PVector xy;
  long time_clicked;
  boolean uncertainty_r;
  
  int rows = 3;
  int cols = 3;
    
  int swidth = int(width/cols);
  int sheight = int(height/rows);
  
  ArrayList stimuli;
  float total_area;
  
  StimulusSet() { //This constructor is used when defining the uncertainty response
    uncertainty_r = true;
  }
  
  StimulusSet(int _num) {
    time_clicked = -1;
    num = _num;
    position = -1;
    uncertainty_r = false;
    
    float target_total_area = swidth*sheight*.1;
    //while (createStimuli(target_total_area) > 5) { } //Keep trying until we get close to our target area
    createStimuli(target_total_area);
  }
  
  float createStimuli(float target_area) {
    //Create a set of stimuli
    //println("Creating " + num + " stimuli with a total area of " + target_area);
    float obtained_total_area = 0;
    
    
    stimuli = new ArrayList();
    int newstimuli = 0;
    for (int i=0;i<num;i++) {
      //println(" stimulus " + (i+1) + " of " + (num));
      
      PVector position;
      float rad=0;
      float area=0;
      
      float max_area = target_area*.784/(num*.5); 
      float min_area = target_area*.784/(num*4);
      
      if (i == num - 1) {
        //If we're defining the last stimulus
        area = target_area - obtained_total_area;
        
        //println("  selecting area = " + area);
      } else {
        //If we're defining the other stimuli
        area = random(min_area,max_area);
        
        //println("  selecting random area = " + area + " random(" + min_area + "," + max_area + ")");
      }
      obtained_total_area += area;
      rad = sqrt(area/PI);
      //println("  radius = " + rad);
      position = findOpenSpace(rad);
      //println("  pos = " + position.x + "," + position.y);
      stimuli.add(new Stimulus(rad,position));
      newstimuli++;
      
    }
    //println(" Created " + newstimuli + " stimuli. Distance from target_area = "  + (target_area - obtained_total_area));
    return target_area - obtained_total_area; //Return the difference between the target area and the area we obtained
  }
  
  PVector findOpenSpace(float _rad) {
    //This is just a lazy brute-force way of finding an open space to draw another stimulus
    PVector tempPosition = randomPosition(_rad);
    int attempts=1;
    //println("  attempt(" + attempts + ") testing position " + tempPosition.x + "," + tempPosition.y + " with radius=" + _rad + " doesOverlap: " + stimulusDoesOverlap(tempPosition,_rad));
    while (stimulusDoesOverlap(tempPosition,_rad)==true && attempts < 300) {
      attempts++;
      tempPosition = randomPosition(_rad);
      //println("  attempt(" + attempts + ") testing position " + tempPosition.x + "," + tempPosition.y + " with radius=" + _rad + " doesOverlap: " + stimulusDoesOverlap(tempPosition,_rad));
    }
    if (stimulusDoesOverlap(tempPosition,_rad) == false) {
      //println("   found openspace after " + attempts + " attempts.");
      return tempPosition;
    } else {
      //println("   failed to find openspace after " + attempts + " attempts.");
      return new PVector(-1,-1);
    }
  }
  
  boolean stimulusDoesOverlap(PVector position, float rad) {
    //Return true if the proposed stimulus overlaps with other stimuli
    for (int i = 0;i<stimuli.size();i++) {
      Stimulus stimulus = (Stimulus) stimuli.get(i);
      if (dist(stimulus.position.x,stimulus.position.y,position.x,position.y) < (stimulus.rad + rad)) return true;
    }
    return false;
  }
  
  PVector randomPosition(float _rad) {
    //choose a random position someone in the space
    return new PVector(int(random(_rad,swidth-_rad)),int(random(_rad,sheight-_rad)));
  }
  
  void drawStimuli() {
    if (stimuli == null) {
      println("ERROR in drawStimuli(), the stimuli arrayList is NULL!!!");
      return;
    }
    pushMatrix();
    translate(xy.x,xy.y);
    for (int i = 0;i<stimuli.size();i++) {
      Stimulus stimulus = (Stimulus) stimuli.get(i);
      stimulus.drawStimulus();
    }
    popMatrix();
  }
  
  void drawAnimatedStimuli(long currentTime, long stageLength) {
    float percent = (float)currentTime/stageLength;
    int numStim = stimuli.size();
    int currentStim = int(percent*(numStim-1));
    println("currenttime: " + currentTime + " stageLength: " + stageLength + " percent_of_trial: " + percent);
    println("  numStim: " + numStim);
    println("  currentStim: " + currentStim);
    pushMatrix();
    translate(xy.x,xy.y);
    Stimulus stimulus = (Stimulus) stimuli.get(currentStim);
    stimulus.drawStimulus();
    popMatrix();
  }
  
  void determineXY() {
    if (position == -1) {
      println("Cannot determineXY, position not set!");
      return;
    }
    int col = (position-1)/rows;
    int row = position - col*rows;
    
    xy = new PVector(0,0);
    
    xy.x = int(swidth * col);
    xy.y = int(sheight * row)-sheight;
  }
  
  void drawAnimatedStimulus(int consequence,long currentTime, long stageLength) {
    if (xy == null) determineXY();

    if (consequence == -1) {
      fill(49,79,79);
    } else if (consequence == 0) {
      //println(" " + consequence + " blue");
      fill(0,0,250);
    } else if (consequence == 1) {
      //println(" " + consequence + " green");
      fill(0,255,0);
    } else if (consequence == 2) {
      //println(" " + consequence + " red");
      fill(255,0,0);
    }
    
    rectMode(CORNER);
    stroke(255,255,255);
    rect(xy.x,xy.y,swidth,sheight);
    
    if (uncertainty_r) {
      fill(0,0,0);
      textFont(createFont("FFScala", 32));
      text("?",xy.x+swidth/2,xy.y+sheight/2);
    } else {
      fill(255,255,255);
      drawAnimatedStimuli(currentTime, stageLength);
      fill(0,0,0);
      textFont(createFont("FFScala", 32));
      //text(num,xy.x+swidth/2,xy.y+sheight/2);
    }
   
    //println("  Drawing Stimulus " + position + " @ " + pos.x + "," + pos.y + "  swidth: " + swidth);
  }
  
  void drawStimulus(int consequence) {
    if (xy == null) determineXY();

    if (consequence == -1) {
      fill(49,79,79);
    } else if (consequence == 0) {
      //println(" " + consequence + " blue");
      fill(0,0,250);
    } else if (consequence == 1) {
      //println(" " + consequence + " green");
      fill(0,255,0);
    } else if (consequence == 2) {
      //println(" " + consequence + " red");
      fill(255,0,0);
    }
    
    rectMode(CORNER);
    stroke(255,255,255);
    rect(xy.x,xy.y,swidth,sheight);
    
    if (uncertainty_r) {
      fill(0,0,0);
      textFont(createFont("FFScala", 32));
      text("?",xy.x+swidth/2,xy.y+sheight/2);
    } else {
      fill(255,255,255);
      drawStimuli();
      fill(0,0,0);
      textFont(createFont("FFScala", 32));
      //text(num,xy.x+swidth/2,xy.y+sheight/2);
    }
   
    //println("  Drawing Stimulus " + position + " @ " + pos.x + "," + pos.y + "  swidth: " + swidth);
  }
  
  boolean click() {
    if (xy == null) determineXY();
    if ((mouseX >= xy.x) && (mouseY >= xy.y) && (mouseX <= xy.x+swidth) && (mouseY <= xy.y+sheight)) {
      time_clicked = millis();
      //println("  clicked " + num);
      return true;
    } else {
      time_clicked = 0;
      return false;
    }
  }
}
